﻿using System;

namespace _33_csharp_面向对象_多播委托
{
    class Program
    {
        static Action action;

        static void Main(string[] args)
        {
            action += ForAction;
            action += ForAction3;
            action += ForAction2; //快捷键是 按住 alt + 上下键 ，调整语句的顺序
            action?.Invoke();

            Console.WriteLine("----------分割线-----------");

            action -= ForAction2;
            action?.Invoke();

            Console.WriteLine("----------分割线-----------");
            var person = new Person();
            action += person.ForAction;// IsStatic  = false
            action += Person.ForAction_s; // IsStatic  = true

            var list = action.GetInvocationList();
            foreach (var item in list)
            {
                Console.WriteLine($"is special= { item.Method.IsSpecialName} , static = {item.Method.IsStatic} ，name = {item.Method.Name}");
            }

            // GetInvoactionList 有啥用？
            //1. 知道 委托中订阅了那些方法 ：见 29 行 ，并且我们通过 Delegate.Target 知道这些方法属于那些实例（如果有的话）
            //2. 可以找到指定的方法，直接调用，见： list[0].Method?.Invoke(null,null);
            //3. 可以判断某个方法是否已经存在，避免重复添加（注册）。

            Console.WriteLine("----------分割线-----------");
            action -= ForAction3; //先移除，保证测试时不存在 ForAction3，用于 测试如果委托中不存在指定名称的方法则添加
            // get：获取
            // Invocation : 调用 ，invoke
            // list ：列表
            // getinvocationlist ：获取执行列表，得到所有添加的方法
            list = action.GetInvocationList();
            string name = nameof(ForAction3);

            Delegate result = Array.Find(list, v => v.Method.Name == name);
            if (result == null)
            {
                action += ForAction3;
                Console.WriteLine("方法添加成功！");
            }
            else
            {
                Console.WriteLine("对不起，方法已经存在，不能重复添加！");
            }
            action?.Invoke();

            // 上面这种查询，只是查询了方法名，而方法在不同的类类型中可以存在相同的方法名
            // 完善：加多几个查询的条件

            Console.WriteLine("----------分割线-----------");
            name = nameof(ForAction);
            action -= ForAction;
            //action -= person.ForAction;
            list = action.GetInvocationList();
            result = Array.Find(list, v =>
            {
                // target : 目标
                object b = v.Target;
                Console.WriteLine(b?.ToString());
                // Method (Function) 方法（函数）
                return v.Method.Name == name && b == null;
            });
            if (result == null)
            {
                Console.WriteLine($"不存在{name},请添加");
            }
            else
            {
                Console.WriteLine($"对不起，方法{name}已经存在，不能重复添加！");
            }

            Console.WriteLine("----------分割线-----------");
            FuncClass fc = new FuncClass();


        }


        // alt + shift + 上下左右键：选中多行同时编辑
        public static void ForAction() => Console.WriteLine(nameof(ForAction));
        public static void ForAction3() => Console.WriteLine(nameof(ForAction3));
        public static void ForAction2() => Console.WriteLine(nameof(ForAction2));


    }

    // 多播委托（多播+委托）：多个，传播，指向的是多个方法。
    // 多播让同一个事情触发时，能够执行多个行为成为可能，一般用在观察者模式
    // 使用 += 添加一个方法，使用 -= 移除一个方法
    // 使用 GetInvocationList() 获取一个委托中监听（添加）的所有方法
    // 多播委托的调用顺序按照方法被添加的顺序执行，先添加先调用
    // 如果是有返回值的委托发生了多播，只能调用到最后一个方法传递过来的返回值

    public delegate void Action();

    public class Person
    {
        public void ForAction()
        {
            Console.WriteLine("Inside Person");
        }
        public static void ForAction_s()
        {
            Console.WriteLine("Inside Persion Static");
        }
    }


    public class FuncClass
    {
        //public Func<int> getint;
        public delegate int GetInt32();
        private GetInt32 getInt;
        int age;
        public int MyProperty
        {
            get => age;
            set => age = value;
        }

        private int RetInt32_01() => 1;

        private int RetInt32_02()
        {
            Console.WriteLine(nameof(RetInt32_02));
            return 2;
        }

        private int RetInt32_03() => 3;

        public FuncClass()
        {
            getInt += RetInt32_03;
            getInt += RetInt32_02;
            getInt += RetInt32_01;

            int? result = getInt?.Invoke();
            Console.WriteLine($"result={ result}");
        }
    }
}
